package com.lanyou.esb.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.lanyou.cook.common.Constants;
import com.lanyou.esb.common.CommonUtils;
import com.lanyou.esb.redis.proxy.impl.ConcurrencyNumberJedisProxy;
import com.lanyou.esb.vo.ConcurrencyNumberVo;
import com.lanyou.esb.vo.ConcurrencyNumberVo.Entry;

/**
 * 并发数服务
 * 
 * @author Davey.wu
 */

@Service
public class ConcurrencyNumberService {
	@Autowired
	private ConcurrencyNumberJedisProxy concurrencyNumberJedisProxy;

	private static FastDateFormat FASTDATEFORMAT_YYYYMMDDHHSS_NOSEPARATOR = FastDateFormat
			.getInstance(Constants.DATETIME_PATTERN_YYYYMMDDHHMMSS_NOSEPARATOR);

	/**
	 * 查询并发数<br>
	 * 并发数计算规则：<br>
	 * N=[(I*0.8*P) /(T*0.2)]*R<br>
	 * I =某时间区间内的接口请求数<br>
	 * P =某时间区间内的接口平均响应时间 单位秒<br>
	 * T =为时间区间值，单位秒<br>
	 * R =调节因子，接口平台缺省为1<br>
	 * 
	 * @param date
	 *            ：统计时间
	 * @param size
	 *            ：区间数
	 * @return
	 * @throws ParseException
	 * @throws IOException
	 * @throws JsonMappingException
	 * @throws JsonParseException
	 */
	public ConcurrencyNumberVo findConcurrencyNumberInfo(Date date, int size)
			throws ParseException, JsonParseException, JsonMappingException,
			IOException {
		// 时间列表
		List<String> timeSections = getDateList(date, size);
		// redis数据查询键集合
		List<String> keys = new ArrayList<>(timeSections.size());
		// redis数据查询键组合
		Map<String, String> keysMap = new HashMap<>(timeSections.size());
		String key = "";
		// 获取redis数据查询键
		for (String timeSection : timeSections) {
			key = concurrencyNumberJedisProxy.generateKey(timeSection);
			keys.add(key);
			keysMap.put(timeSection, key);
		}
		// 从REDIS中读取流量数据
		Map<String, Double> values = concurrencyNumberJedisProxy.get(keys);

		// 数据dateList
		List<Entry> entrys = new ArrayList<>(10);
		ConcurrencyNumberVo result = new ConcurrencyNumberVo();
		result.setEntrys(entrys);
		Double value = null;
		for (String timeSection : timeSections) {
			key = keysMap.get(timeSection);
			ConcurrencyNumberVo.Entry entry = new Entry();
			entry.setKey(FASTDATEFORMAT_YYYYMMDDHHSS_NOSEPARATOR.parse(
					timeSection).getTime());
			value = values.get(key);
			if (value == null) {
				value = 0.0;
			}
			value = calculateConcurrencyNumber(value);
			BigDecimal b = new BigDecimal(value);
			value = b.setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
			entry.setValue(value);
			entrys.add(entry);
		}
		return result;
	}

	/**
	 * 获取某个时间点的并发数
	 * 
	 * @param date
	 *            ：目标时间点
	 * @return
	 * @throws IOException
	 * @throws JsonMappingException
	 * @throws JsonParseException
	 */
	public double findLastConcurrencyNumberInfo(Date date)
			throws JsonParseException, JsonMappingException, IOException {
		if (date == null) {
			return 0;
		}
		double value = concurrencyNumberJedisProxy
				.get(concurrencyNumberJedisProxy.generateKey(date));
		value = calculateConcurrencyNumber(value);
		return value;
	}

	/**
	 * 计算并发数
	 * 
	 * @param value
	 * @return
	 */
	private double calculateConcurrencyNumber(double value) {
		return 0.8 * value / 0.2;
	}

	/**
	 * 获取日期列表
	 * 
	 * @param startDate
	 *            ：开始日期
	 * @param endDate
	 *            ：结束日期
	 * @return
	 */
	private List<String> getDateList(Date date, int size) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.MILLISECOND, 0);
		String[] list = new String[size];
		// 获取日期列表
		while ((--size) >= 0) {
			list[size] = FASTDATEFORMAT_YYYYMMDDHHSS_NOSEPARATOR
					.format(calendar);
			// 每隔一秒取一个时间点
			calendar.add(Calendar.SECOND,
					-CommonUtils.CONCURRENCY_NUMBER_TIME_SEPARATOR);
		}
		return Arrays.asList(list);
	}
}
